module storage_plaintext;

import std.file;
import std.stdio;
import std.string;

import storage;
import database;
import table;

class PlainTextStorage : Storage
{
  this() {}

  override bool load(Database d) {
    d.clear();
    string db_name = "./" ~ d.getName();

    foreach(string name; dirEntries(".", SpanMode.shallow)) {
      if (indexOf(name,db_name) != 0)
        continue;

      string table_name = name[db_name.length + 1 .. indexOf(name,".dat")];
      
      auto table = new Table(table_name);
      auto f = new File(name,"r");
      f.readln(); // col num

      // Reading headers
      auto headers_str = f.readln();
      foreach(string header_string; splitLines(tr(headers_str,"\t","\n"))) {
        if (!header_string.length) continue;
        table.addColumn(new Column(new Header(header_string)));
      }

      // Reading rows
      Row r;
      auto columns = table.getColumns();
      while(!f.eof()) {
        string line = f.readln();
        if (!line.length) continue;
        r.length = 0; r.length = columns.length;
        foreach(int col, string column; splitLines(tr(line,"\t","\n"))) {
          if (!column.length) continue;
          r[col] = EntryFactory(column, columns[col].getHeader().type);
        }
        table.addRow(r.dup);
      }

      d.addTable(table);
    }
    return true;
  }

  override bool save(Database d) {
    string db_name = "./" ~ d.getName();

    // Create backup
    foreach(string name; dirEntries(".", SpanMode.shallow)) {
      if (indexOf(name,db_name) == 0)
        std.file.copy(name, name ~ ".bak");
    }

    // Remove old files
    foreach(string name; dirEntries(".", SpanMode.shallow)) {
      if (indexOf(name,db_name) == 0)
        std.file.remove(name);
    }

    // Dump the data to files
    auto allRows = delegate (Row r) { return true; };
    foreach(table; d.getTables()) {
      auto f = File(db_name ~ "_" ~ table.getName() ~ ".dat", "w");
      f.writeln(table.getColumns().length);
      foreach(column; table.getColumns()) {
        f.write(column.getHeader().toStringRepr() ~ "\t");
      }
      f.writeln("");
      foreach(row; table.getRows(allRows)) {
        foreach(entry; row) {
          if (entry)
            f.write(entry.toStringRepr() ~ "\t");
        }
        f.writeln("");
      }
    }

    // Remove backups
    foreach(string name; dirEntries(".", SpanMode.shallow)) {
      if (indexOf(name,db_name) == 0 && indexOf(name,".bak") != -1)
        std.file.remove(name);
    }

    return true;
  }

  override bool remove(Database d) {
    string db_name = "./" ~ d.getName();
    foreach(string name; dirEntries(".", SpanMode.shallow)) {
      if (indexOf(name, db_name) == 0)
        std.file.remove(name);
    }
    return true;
  }

  override bool exists(Database d) {
    bool found = false;
    string db_name = "./" ~ d.getName();
    foreach(string name; dirEntries(".", SpanMode.shallow)) {
      if (indexOf(name, db_name) == 0) {
        found = true;
        break;
      }
    }
    return found;
  }
}
